home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cpp.arc / FLOATCPP.C < prev    next >
C/C++ Source or Header  |  1985-11-27  |  39KB  |  1,258 lines

  1.  
  2. From:   RHEA::DECWRL::"elsie!ado@seismo.ARPA" 11-JUN-1985 15:52
  3. To:     seismo!minow%rex.DEC@decwrl
  4. Subj:   cpp
  5.  
  6. Received: from DECWRL by DEC-RHEA with SMTP; Tue, 11 Jun 85 12:50-PDT
  7. Received: from seismo.ARPA (seismo.arpa.ARPA) by decwrl.ARPA (4.22.01/4.7.34)
  8.         id AA21114; Tue, 11 Jun 85 12:47:28 pdt
  9. Received: from elsie.UUCP by seismo.ARPA with UUCP; Tue, 11 Jun 85 15:44:45 EDT
  10. Date: Tue, 11 Jun 85 15:44:45 EDT
  11. Return-Path: <elsie!ado@seismo.ARPA>
  12. Message-Id: <8506111944.AA14028@seismo.ARPA>
  13.  
  14. I've made my first, surely bug-ridden, try at handling floating point values in
  15. "#if" directives.  We'll be running it here at elsie to see what happens.
  16. The only thing that changes is "cpp5.c", which appears below.
  17.  
  18. Signed/unsigned work surely needs to be done.
  19. There's also no checking for bogus stuff such as
  20.         #if 5.0 | 4.0
  21. although stuff such as
  22.         #if 5.2 | 4.2
  23. could fairly easily be detected by checking
  24.         x == (long) x
  25. when converting from a double to a long in "evaleval".
  26.  
  27.                                 --ado
  28.  
  29. /*
  30.  *                          C P P 5 . C
  31.  *              E x p r e s s i o n   E v a l u a t i o n
  32.  *
  33.  * Edit History
  34.  * 31-Aug-84    MM      USENET net.sources release
  35.  * 04-Oct-84    MM      __LINE__ and __FILE__ must call ungetstring()
  36.  *                      so they work correctly with token concatenation.
  37.  *                      Added string formal recognition.
  38.  * 25-Oct-84    MM      "Short-circuit" evaluate #if's so that we
  39.  *                      don't print unnecessary error messages for
  40.  *                      #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  41.  * 31-Oct-84    ado/MM  Added token concatenation
  42.  *  6-Nov-84    MM      Split from #define stuff, added sizeof stuff
  43.  * 19-Nov-84    ado     #if error returns TRUE for (sigh) compatibility
  44.  * 22-Apr-85    ado/MM  added evalone to properly handle \value
  45.  * 29-Apr-85    ado     Cleaned up #if ... sizeof
  46.  */
  47.  
  48. #include        <stdio.h>
  49. #include        <ctype.h>
  50. #include        "cppdef.h"
  51. #include        "cpp.h"
  52.  
  53. /*
  54.  * Evaluate an #if expression.
  55.  */
  56.  
  57. static char     *opname[] = {           /* For debug and error messages */
  58. "end of expression", "val", "id",
  59.   "+",   "-",  "*",  "/",  "%",
  60.   "<<", ">>",  "&",  "|",  "^",
  61.   "==", "!=",  "<", "<=", ">=",  ">",
  62.   "&&", "||",  "?",  ":",  ",",
  63.   "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
  64. };
  65.  
  66. /*
  67.  * opdope[] has the operator precedence:
  68.  *     Bits
  69.  *        7     Unused (so the value is always positive)
  70.  *      6-2     Precedence (000x .. 017x)
  71.  *      1-0     Binary op. flags:
  72.  *          01  The binop flag should be set/cleared when this op is seen.
  73.  *          10  The new value of the binop flag.
  74.  * Note:  Expected, New binop
  75.  * constant     0       1       Binop, end, or ) should follow constants
  76.  * End of line  1       0       End may not be preceeded by an operator
  77.  * binary       1       0       Binary op follows a value, value follows.
  78.  * unary        0       0       Unary op doesn't follow a value, value follows
  79.  *   (          0       0       Doesn't follow value, value or unop follows
  80.  *   )          1       1       Follows value.  Op follows.
  81.  */
  82.  
  83. static char     opdope[OP_MAX] = {
  84.   0001,                                 /* End of expression            */
  85.   0002,                                 /* Digit                        */
  86.   0000,                                 /* Letter (identifier)          */
  87.   0141, 0141, 0151, 0151, 0151,         /* ADD, SUB, MUL, DIV, MOD      */
  88.   0131, 0131, 0101, 0071, 0071,         /* ASL, ASR, AND,  OR, XOR      */
  89.   0111, 0111, 0121, 0121, 0121, 0121,   /*  EQ,  NE,  LT,  LE,  GE,  GT */
  90.   0061, 0051, 0041, 0041, 0031,         /* ANA, ORO, QUE, COL, CMA      */
  91. /*
  92.  * Unary op's follow
  93.  */
  94.   0160, 0160, 0160, 0160,               /* NEG, PLU, COM, NOT           */
  95.   0170, 0013, 0023,                     /* LPA, RPA, END                */
  96. };
  97. /*
  98.  * OP_QUE and OP_RPA have alternate precedences:
  99.  */
  100. #define OP_RPA_PREC     0013
  101. #define OP_QUE_PREC     0034
  102.  
  103. /*
  104.  * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
  105.  *      #if FOO != 0 && 10 / FOO ...
  106.  * doesn't generate an error message.  They are stored in optab.skip.
  107.  */
  108. #define S_ANDOR         2
  109. #define S_QUEST         1
  110.  
  111. typedef struct optab {
  112.     char        op;                     /* Operator                     */
  113.     char        prec;                   /* Its precedence               */
  114.     char        skip;                   /* Short-circuit: TRUE to skip  */
  115. } OPTAB;
  116. static double   evalue;                 /* Current value from evallex() */
  117.  
  118. #ifdef  nomacargs
  119. FILE_LOCAL int
  120. isbinary(op)
  121. register int    op;
  122. {
  123.         return (op >= FIRST_BINOP && op <= LAST_BINOP);
  124. }
  125.  
  126. FILE_LOCAL int
  127. isunary(op)
  128. register int    op;
  129. {
  130.         return (op >= FIRST_UNOP && op <= LAST_UNOP);
  131. }
  132. #else
  133. #define isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
  134. #define isunary(op)     (op >= FIRST_UNOP  && op <= LAST_UNOP)
  135. #endif
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149. /*
  150.  * The following definitions are used to specify basic variable sizes.
  151.  */
  152.  
  153. #ifndef S_CHAR
  154. #define S_CHAR          (sizeof (char))
  155. #endif
  156. #ifndef S_SINT
  157. #define S_SINT          (sizeof (short int))
  158. #endif
  159. #ifndef S_INT
  160. #define S_INT           (sizeof (int))
  161. #endif
  162. #ifndef S_LINT
  163. #define S_LINT          (sizeof (long int))
  164. #endif
  165. #ifndef S_FLOAT
  166. #define S_FLOAT         (sizeof (float))
  167. #endif
  168. #ifndef S_DOUBLE
  169. #define S_DOUBLE        (sizeof (double))
  170. #endif
  171. #ifndef S_PCHAR
  172. #define S_PCHAR         (sizeof (char *))
  173. #endif
  174. #ifndef S_PSINT
  175. #define S_PSINT         (sizeof (short int *))
  176. #endif
  177. #ifndef S_PINT
  178. #define S_PINT          (sizeof (int *))
  179. #endif
  180. #ifndef S_PLINT
  181. #define S_PLINT         (sizeof (long int *))
  182. #endif
  183. #ifndef S_PFLOAT
  184. #define S_PFLOAT        (sizeof (float *))
  185. #endif
  186. #ifndef S_PDOUBLE
  187. #define S_PDOUBLE       (sizeof (double *))
  188. #endif
  189. #ifndef S_PFPTR
  190. #define S_PFPTR         (sizeof (int (*)()))
  191. #endif
  192.  
  193.  
  194.  
  195.  
  196.  
  197. typedef struct types {
  198.     short       type;                   /* This is the bit if           */
  199.     char        *name;                  /* this is the token word       */
  200.     short       excluded;               /* but these aren't legal here  */
  201. } TYPES;
  202.  
  203. #define ANYSIGN         (T_SIGNED | T_UNSIGNED)
  204. #define ANYFLOAT        (T_FLOAT  | T_DOUBLE)
  205. #define ANYINT          (T_CHAR   | T_SHORT | T_INT | T_LONG)
  206.  
  207. static TYPES basic_types[] = {
  208.         T_CHAR,         "char",         ANYFLOAT | ANYINT,
  209.         T_INT,          "int",          ANYFLOAT | T_CHAR | T_INT,
  210.         T_FLOAT,        "float",        ANYFLOAT | ANYINT | ANYSIGN,
  211.         T_DOUBLE,       "double",       ANYFLOAT | ANYINT | ANYSIGN,
  212.         T_SHORT,        "short",        ANYFLOAT | ANYINT,
  213.         T_LONG,         "long",         ANYFLOAT | ANYINT,
  214.         T_SIGNED,       "signed",       ANYFLOAT | ANYINT | T_CHAR | T_INT,
  215.         T_UNSIGNED,     "unsigned",     ANYFLOAT | ANYINT | T_CHAR | T_INT,
  216.         0,              NULL,           0       /* Signal end           */
  217. };
  218.  
  219.  
  220. /*
  221.  * The order of this table is important -- it is also referenced by
  222.  * the command line processor to allow run-time overriding of the
  223.  * built-in size values.  The order must not be changed:
  224.  *      char, short, int, long, float, double (func pointer)
  225.  */
  226. SIZES size_table[] = {
  227.     { T_CHAR,   S_CHAR,         S_PCHAR         },      /* char         */
  228.     { T_SHORT,  S_SINT,         S_PSINT         },      /* short int    */
  229.     { T_INT,    S_INT,          S_PINT          },      /* int          */
  230.     { T_LONG,   S_LINT,         S_PLINT         },      /* long         */
  231.     { T_FLOAT,  S_FLOAT,        S_PFLOAT        },      /* float        */
  232.     { T_DOUBLE, S_DOUBLE,       S_PDOUBLE       },      /* double       */
  233.     { T_FPTR,   0,              S_PFPTR         },      /* int (*())    */
  234.     { 0,        0,              0               },      /* End of table */
  235. };
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245. int
  246. eval()
  247. /*
  248.  * Evaluate an expression.  Straight-forward operator precedence.
  249.  * This is called from control() on encountering an #if statement.
  250.  * It calls the following routines:
  251.  * evallex      Lexical analyser -- returns the type and value of
  252.  *              the next input token.
  253.  * evaleval     Evaluate the current operator, given the values on
  254.  *              the value stack.  Returns a pointer to the (new)
  255.  *              value stack.
  256.  * For compatiblity with older cpp's, this return returns 1 (TRUE)
  257.  * if a syntax error is detected.
  258.  */
  259. {
  260.         register int    op;             /* Current operator             */
  261.         register double *valp;          /* -> value vector              */
  262.         register OPTAB  *opp;           /* Operator stack               */
  263.         int             prec;           /* Op precedence                */
  264.         int             binop;          /* Set if binary op. needed     */
  265.         int             op1;            /* Operand from stack           */
  266.         int             skip;           /* For short-circuit testing    */
  267.         double          value[NEXP];    /* Value stack                  */
  268.         OPTAB           opstack[NEXP];  /* Operand stack                */
  269.         extern double   *evaleval();    /* Does actual evaluation       */
  270.  
  271.         valp = value;
  272.         opp = opstack;
  273.         opp->op = OP_END;               /* Mark bottom of stack         */
  274.         opp->prec = opdope[OP_END];     /* And its precedence           */
  275.         opp->skip = 0;                  /* Not skipping now             */
  276.         binop = 0;
  277. again:  ;
  278. #ifdef  DEBUG_EVAL
  279.         printf("In #if at again: skip = %d, binop = %d, line is: %s",
  280.             opp->skip, binop, infile->bptr);
  281. #endif
  282.         if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
  283.             op = OP_NEG;                        /* Unary minus          */
  284.         else if (op == OP_ADD && binop == 0)
  285.             op = OP_PLU;                        /* Unary plus           */
  286.         else if (op == OP_FAIL)
  287.             return (1);                         /* Error in evallex     */
  288. #ifdef  DEBUG_EVAL
  289.         printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
  290.             opname[op], opdope[op], binop, opp->skip);
  291. #endif
  292.         if (op == DIG) {                        /* Value?               */
  293.             if (binop != 0) {
  294.                 cerror("misplaced constant in #if", NULLST);
  295.                 return (1);
  296.             }
  297.             else if (valp >= &value[NEXP-1]) {
  298.                 cerror("#if value stack overflow", NULLST);
  299.                 return (1);
  300.             }
  301.             else {
  302. #ifdef  DEBUG_EVAL
  303.                 printf("pushing %f onto value stack[%d]\n",
  304.                     evalue, valp - value);
  305. #endif
  306.                 *valp++ = evalue;
  307.                 binop = 1;
  308.             }
  309.             goto again;
  310.         }
  311.         else if (op > OP_END) {
  312.             cerror("Illegal #if line", NULLST);
  313.             return (1);
  314.         }
  315.         prec = opdope[op];
  316.         if (binop != (prec & 1)) {
  317.             cerror("Operator %s in incorrect context", opname[op]);
  318.             return (1);
  319.         }
  320.         binop = (prec & 2) >> 1;
  321.         for (;;) {
  322. #ifdef  DEBUG_EVAL
  323.             printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
  324.                 opname[op], prec, opname[opp->op], opp->prec, opp->skip);
  325. #endif
  326.             if (prec > opp->prec) {
  327.                 if (op == OP_LPA)
  328.                     prec = OP_RPA_PREC;
  329.                 else if (op == OP_QUE)
  330.                     prec = OP_QUE_PREC;
  331.                 op1 = opp->skip;                /* Save skip for test   */
  332.                 /*
  333.                  * Push operator onto op. stack.
  334.                  */
  335.                 opp++;
  336.                 if (opp >= &opstack[NEXP]) {
  337.                     cerror("expression stack overflow at op \"%s\"",
  338.                         opname[op]);
  339.                     return (1);
  340.                 }
  341.                 opp->op = op;
  342.                 opp->prec = prec;
  343.                 skip = (valp[-1] != 0);         /* Short-circuit tester */
  344.                 /*
  345.                  * Do the short-circuit stuff here.  Short-circuiting
  346.                  * stops automagically when operators are evaluated.
  347.                  */
  348.                 if ((op == OP_ANA && !skip)
  349.                  || (op == OP_ORO && skip))
  350.                     opp->skip = S_ANDOR;        /* And/or skip starts   */
  351.                 else if (op == OP_QUE)          /* Start of ?: operator */
  352.                     opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
  353.                 else if (op == OP_COL) {        /* : inverts S_QUEST    */
  354.                     opp->skip = (op1 & S_ANDOR)
  355.                               | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
  356.                 }
  357.                 else {                          /* Other ops leave      */
  358.                     opp->skip = op1;            /*  skipping unchanged. */
  359.                 }
  360. #ifdef  DEBUG_EVAL
  361.                 printf("stacking %s, valp[-1] == %d at %s",
  362.                     opname[op], valp[-1], infile->bptr);
  363.                 dumpstack(opstack, opp, value, valp);
  364. #endif
  365.                 goto again;
  366.             }
  367.             /*
  368.              * Pop operator from op. stack and evaluate it.
  369.              * End of stack and '(' are specials.
  370.              */
  371.             skip = opp->skip;                   /* Remember skip value  */
  372.             switch ((op1 = opp->op)) {          /* Look at stacked op   */
  373.             case OP_END:                        /* Stack end marker     */
  374.                 if (op == OP_EOE)
  375.                     return (valp[-1]);          /* Finished ok.         */
  376.                 goto again;                     /* Read another op.     */
  377.  
  378.             case OP_LPA:                        /* ( on stack           */
  379.                 if (op != OP_RPA) {             /* Matches ) on input   */
  380.                     cerror("unbalanced paren's, op is \"%s\"", opname[op]);
  381.                     return (1);
  382.                 }
  383.                 opp--;                          /* Unstack it           */
  384.                 /* goto again;                  -- Fall through         */
  385.  
  386.             case OP_QUE:
  387.                 goto again;                     /* Evaluate true expr.  */
  388.  
  389.             case OP_COL:                        /* : on stack.          */
  390.                 opp--;                          /* Unstack :            */
  391.                 if (opp->op != OP_QUE) {        /* Matches ? on stack?  */
  392.                     cerror("Misplaced '?' or ':', previous operator is %s",
  393.                         opname[opp->op]);
  394.                     return (1);
  395.                 }
  396.                 /*
  397.                  * Evaluate op1.
  398.                  */
  399.             default:                            /* Others:              */
  400.                 opp--;                          /* Unstack the operator */
  401. #ifdef  DEBUG_EVAL
  402.                 printf("Stack before evaluation of %s\n", opname[op1]);
  403.                 dumpstack(opstack, opp, value, valp);
  404. #endif
  405.                 valp = evaleval(valp, op1, skip);
  406. #ifdef  DEBUG_EVAL
  407.                 printf("Stack after evaluation\n");
  408.                 dumpstack(opstack, opp, value, valp);
  409. #endif
  410.             }                                   /* op1 switch end       */
  411.         }                                       /* Stack unwind loop    */
  412. }
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. FILE_LOCAL int
  438. evallex(skip)
  439. int             skip;           /* TRUE if short-circuit evaluation     */
  440. /*
  441.  * Return next eval operator or value.  Called from eval().  It
  442.  * calls a special-purpose routines for 'char' strings and
  443.  * numeric values:
  444.  * evalchar     called to evaluate 'x'
  445.  * evalnum      called to evaluate numbers.
  446.  */
  447. {
  448.         register int    c, c1, t;
  449.         extern double   evalnum();
  450.  
  451. again:  do {                                    /* Collect the token    */
  452.             c = skipws();
  453.             if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
  454.                 unget();
  455.                 return (OP_EOE);                /* End of expression    */
  456.             }
  457.         } while ((t = type[c]) == LET && catenate());
  458.         if (t == INV) {                         /* Total nonsense       */
  459.             if (!skip) {
  460.                 if (isascii(c) && isprint(c))
  461.                     cierror("illegal character '%c' in #if", c);
  462.                 else
  463.                     cierror("illegal character (%d decimal) in #if", c);
  464.             }
  465.             return (OP_FAIL);
  466.         }
  467.         else if (t == QUO) {                    /* ' or "               */
  468.             if (c == '\'') {                    /* Character constant   */
  469.                 evalue = evalchar(skip);        /* Somewhat messy       */
  470. #ifdef  DEBUG_EVAL
  471.                 printf("evalchar returns %d.\n", evalue);
  472. #endif
  473.                 return (DIG);                   /* Return a value       */
  474.             }
  475.             cerror("Can't use a string in an #if", NULLST);
  476.             return (OP_FAIL);
  477.         }
  478.         else if (t == LET) {                    /* ID must be a macro   */
  479.             if (streq(token, "defined")) {      /* Or defined name      */
  480.                 c1 = c = skipws();
  481.                 if (c == '(')                   /* Allow defined(name)  */
  482.                     c = skipws();
  483.                 if (type[c] == LET) {
  484.                     evalue = (lookid(c) != NULL);
  485.                     if (c1 != '('               /* Need to balance      */
  486.                      || skipws() == ')')        /* Did we balance?      */
  487.                         return (DIG);           /* Parsed ok            */
  488.                 }
  489.                 cerror("Bad #if ... defined() syntax", NULLST);
  490.                 return (OP_FAIL);
  491.             }
  492.             else if (streq(token, "sizeof"))    /* New sizeof hackery   */
  493.                 return (dosizeof());            /* Gets own routine     */
  494.             /*
  495.              * The Draft ANSI C Standard says that an undefined symbol
  496.              * in an #if has the value zero.  We are a bit pickier,
  497.              * warning except where the programmer was careful to write
  498.              *          #if defined(foo) ? foo : 0
  499.              */
  500.             if (!skip)
  501.                 cwarn("undefined symbol \"%s\" in #if, 0 used", token);
  502.             evalue = 0;
  503.             return (DIG);
  504.         }
  505.         else if (t == DIG) {                    /* Numbers are harder   */
  506.             evalue = evalnum(c);
  507. #ifdef  DEBUG_EVAL
  508.             printf("evalnum returns %d.\n", evalue);
  509. #endif
  510.         }
  511.         else if (c == '.') {
  512.                 c = cget();
  513.                 if (isascii(c) && isdigit(c)) {
  514.                         unget();
  515.                         evalue = evalnum('.');
  516.                         return DIG;
  517.                 }
  518.                 unget();
  519.         }
  520.         else if (strchr("!=<>&|\\", c) != NULL) {
  521.             /*
  522.              * Process a possible multi-byte lexeme.
  523.              */
  524.             c1 = cget();                        /* Peek at next char    */
  525.             switch (c) {
  526.             case '!':
  527.                 if (c1 == '=')
  528.                     return (OP_NE);
  529.                 break;
  530.  
  531.             case '=':
  532.                 if (c1 != '=') {                /* Can't say a=b in #if */
  533.                     unget();
  534.                     cerror("= not allowed in #if", NULLST);
  535.                     return (OP_FAIL);
  536.                 }
  537.                 return (OP_EQ);
  538.  
  539.             case '>':
  540.             case '<':
  541.                 if (c1 == c)
  542.                     return ((c == '<') ? OP_ASL : OP_ASR);
  543.                 else if (c1 == '=')
  544.                     return ((c == '<') ? OP_LE  : OP_GE);
  545.                 break;
  546.  
  547.             case '|':
  548.             case '&':
  549.                 if (c1 == c)
  550.                     return ((c == '|') ? OP_ORO : OP_ANA);
  551.                 break;
  552.  
  553.             case '\\':
  554.                 if (c1 == '\n')                 /* Multi-line if        */
  555.                     goto again;
  556.                 cerror("Unexpected \\ in #if", NULLST);
  557.                 return (OP_FAIL);
  558.             }
  559.             unget();
  560.         }
  561.         return (t);
  562. }
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581. FILE_LOCAL int
  582. dosizeof()
  583. /*
  584.  * Process the sizeof (basic type) operation in an #if string.
  585.  * Sets evalue to the size and returns
  586.  *      DIG             success
  587.  *      OP_FAIL         bad parse or something.
  588.  */
  589. {
  590.         register int    c;
  591.         register TYPES  *tp;
  592.         register SIZES  *sizp;
  593.         short           typecode;
  594.  
  595.         if ((c = skipws()) != '(')
  596.             goto nogood;
  597.         /*
  598.          * Scan off the tokens.
  599.          */
  600.         typecode = 0;
  601.         while ((c = skipws())) {
  602.             if ((c = macroid(c)) == EOF_CHAR || c == '\n')
  603.                 goto nogood;                    /* End of line is a bug */
  604.             else if (c == '(') {                /* thing (*)() func ptr */
  605.                 if (skipws() == '*'
  606.                  && skipws() == ')') {          /* We found (*)         */
  607.                     if (skipws() != '(')        /* Let () be optional   */
  608.                         unget();
  609.                     else if (skipws() != ')')
  610.                         goto nogood;
  611.                     typecode |= T_FPTR;         /* Function pointer     */
  612.                 }
  613.                 else {                          /* Junk is a bug        */
  614.                     goto nogood;
  615.                 }
  616.             }
  617.             else if (type[c] != LET)            /* Exit if not a type   */
  618.                 break;
  619.             else if (!catenate()) {             /* Maybe combine tokens */
  620.                 /*
  621.                  * Look for this unexpandable token in basic_types.
  622.                  */
  623.                 for (tp = basic_types; tp->name != NULLST; tp++) {
  624.                     if (streq(token, tp->name))
  625.                         break;
  626.                 }
  627.                 if (tp->name == NULLST) {
  628.                     cerror("#if sizeof, unknown type \"%s\"", token);
  629.                     return (OP_FAIL);
  630.                 }
  631.                 if ((typecode & tp->excluded) != 0) {
  632.                     cerror("#if sizeof: illegal type combination", NULLST);
  633.                     return (OP_FAIL);
  634.                 }
  635.                 typecode |= tp->type;           /* Or in the type bit   */
  636.             }
  637.         }
  638.         /*
  639.          * We are at the end of the type scan.  Chew off '*' if necessary.
  640.          */
  641.         if (c == '*') {
  642.             typecode |= T_PTR;
  643.             c = skipws();
  644.         }
  645.         if (c == ')') {                         /* Last syntax check    */
  646.             /*
  647.              * We assume that all function pointers are the same size:
  648.              *          sizeof (int (*)()) == sizeof (float (*)())
  649.              * We assume that signed and unsigned don't change the size:
  650.              *          sizeof (signed int) == (sizeof unsigned int)
  651.              */
  652.             if ((typecode & T_FPTR) != 0)       /* Function pointer     */
  653.                 typecode = T_FPTR | T_PTR;
  654.             else {                              /* Var or var * datum   */
  655.                 typecode &= ~(T_SIGNED | T_UNSIGNED);
  656.                 if ((typecode & (T_SHORT | T_LONG)) != 0)
  657.                     typecode &= ~T_INT;
  658.             }
  659.             if ((typecode & ~T_PTR) == 0) {
  660.                 cerror("#if sizeof() error, no type specified", NULLST);
  661.                 return (OP_FAIL);
  662.             }
  663.             /*
  664.              * Exactly one bit (and possibly T_PTR) may be set.
  665.              */
  666.             for (sizp = size_table; sizp->bits != 0; sizp++) {
  667.                 if ((typecode & ~T_PTR) == sizp->bits) {
  668.                     evalue = ((typecode & T_PTR) != 0)
  669.                         ? sizp->psize : sizp->size;
  670.                     return (DIG);
  671.                 }
  672.             }                                   /* We shouldn't fail    */
  673.             cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
  674.             return (OP_FAIL);
  675.         }
  676.  
  677. nogood: unget();
  678.         cerror("#if ... sizeof() syntax error", NULLST);
  679.         return (OP_FAIL);
  680. }
  681.  
  682.  
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701. FILE_LOCAL double
  702. e(n)
  703. register int    n;
  704. {
  705.         register double result;
  706.         register int    isneg;
  707.  
  708.         isneg = n < 0;
  709.         if (isneg)
  710.                 n = -n;
  711.         result = 1;
  712.         while (n > 0) {
  713.                 result *= 10;
  714.                 --n;
  715.         }
  716.         return isneg ? (1 / result) : result;
  717. }
  718.  
  719. FILE_LOCAL int
  720. ctoi(c)
  721. register int    c;
  722. {
  723.         register char * cp;
  724.         register char * dp;
  725.         extern char *   index();
  726.  
  727.         if (isascii(c) && isupper(c))
  728.                 c = tolower(c);
  729.         cp = "0123456789abcdef";
  730.         dp = index(cp, c);
  731.         return (dp == 0) ? -1 : (dp - cp);
  732. }
  733.  
  734. FILE_LOCAL double;
  735. purenumb(base, resultp)
  736. double *        resultp;
  737. {
  738.         register int    digits;
  739.         register int    new;
  740.         register int    c;
  741.  
  742.         *resultp = 0;
  743.         digits = 0;
  744.         for ( ; ; ) {
  745.                 c = cget();
  746.                 new = ctoi(c);
  747.                 if (new < 0 || new >= base) {
  748.                         unget();
  749.                         return digits;
  750.                 }
  751.                 *resultp *= base;
  752.                 *resultp += new;
  753.                 ++digits;
  754.         }
  755. }
  756.  
  757. FILE_LOCAL double
  758. evalnum(c)
  759. register int    c;
  760. /*
  761.  * Expand number for #if lexical analysis.  Note: evalnum recognizes
  762.  * the unsigned suffix, but only returns a signed int value.
  763.  * c may be '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', or '.'.
  764.  */
  765. {
  766.         register int    base;
  767.         register int    ucount, lcount;
  768.         register int    expsignchar;
  769.         register double result, fracpart, exppart;
  770.         register double divisor;
  771.         register int    intdigs, fracdigs;
  772.  
  773.         if (c != '0') {
  774.                 base = 10;
  775.                 unget();
  776.         } else if ((c = cget()) == 'x' || c == 'X') {
  777.                 base = 16;
  778.         } else {
  779.                 base = 8;
  780.                 unget();
  781.         }
  782.         intdigs = purenumb(base, &result);
  783.         c = cget();
  784.         if (c != '.' && c != 'e' && c != 'E') {
  785.                 if (base == 16 && intdigs == 0) {
  786.                         /* "0[xX][^0-9a-fA-F]" */
  787.                         unget();        /* whatever follows the 'x' or 'X' */
  788.                         unget();        /* the 'x' or 'X' */
  789.                         return 0;
  790.                 }
  791.                 ucount = lcount = 0;
  792.                 for ( ; ; ) {
  793.                         switch (c) {
  794.                                 case 'u': case 'U':
  795.                                         if (ucount != 0)
  796.                                                 break;
  797.                                         ++ucount;
  798.                                         c = cget();
  799.                                         continue;
  800.                                 case 'l': case 'L':
  801.                                         if (lcount != 0)
  802.                                                 break;
  803.                                         ++lcount;
  804.                                         c = cget();
  805.                                         continue;
  806.                         }
  807.                         break;
  808.                 }
  809.                 unget();
  810.                 return result;
  811.         }
  812.         /* We get here if c == '.'  || c == 'e' || c == 'E' */
  813.         if (base != 10) {
  814.                 if (base == 16 && intdigs == 0) {
  815.                         /* "0[xX]." */
  816.                         unget();        /* the '.' */
  817.                         unget();        /* the 'x' or 'X' */
  818.                         return 0;
  819.                 }
  820.                 unget();
  821.                 return result;
  822.         }
  823.         if (c == '.') {
  824.                 fracdigs = purenumb(10, &fracpart);
  825.                 if (fracdigs != 0)
  826.                         result += fracpart / e(fracdigs);
  827.                 if ((c = cget()) != 'e' && c != 'E') {
  828.                         unget();
  829.                         return result;
  830.                 }
  831.         }
  832.         if ((c = cget()) == '-' || c == '+')
  833.                 expsignchar = c;
  834.         else {
  835.                 expsignchar = '\0';
  836.                 unget();
  837.         }
  838.         if (purenumb(10, &exppart) <= 0) {
  839.                 if (expsignchar != '\0')
  840.                         unget();
  841.                 unget();        /* the 'e' or 'E' */
  842.                 return result;
  843.         }
  844.         return result * e((expsignchar == '-') ? (int) -exppart : (int) exppart);
  845. }
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868. FILE_LOCAL int
  869. evalchar(skip)
  870. int             skip;           /* TRUE if short-circuit evaluation     */
  871. /*
  872.  * Get a character constant
  873.  */
  874. {
  875.         register int    c;
  876.         register int    value;
  877. #if BIG_ENDIAN
  878.         register int    count;
  879. #endif
  880.  
  881.         instring = TRUE;
  882.         if ((value = evalone()) == EOF_CHAR) {
  883.             switch (cget()) {
  884.             case '\'':                  /* Empty char constant          */
  885.                 cerror("Empty character constant", NULLST);
  886.                 return (0);
  887.  
  888.             /* case '\n':               -- Unterminated char constant   */
  889.             default:                    /* Junk or eof                  */
  890.                 cerror("Unterminated character constant", NULLST);
  891.                 return (0);
  892.             }
  893.         }
  894.         /*
  895.          * We warn on multi-byte constants and try to hack
  896.          * (big|little)endian machines.
  897.          */
  898. #if BIG_ENDIAN
  899.         count = 0;
  900. #endif
  901.         while ((c = evalone()) != EOF_CHAR) {
  902.             if (!skip)
  903.                 ciwarn("multi-byte constant '%c' isn't portable", c);
  904. #if BIG_ENDIAN
  905.             count += BITS_CHAR;
  906.             value += (c << count);
  907. #else
  908.             value <<= BITS_CHAR;
  909.             value += c;
  910. #endif
  911.         }
  912.         switch (cget()) {
  913.         case '\'':                      /* Normal char termination      */
  914.             break;
  915.  
  916.         /* case '\n':                   -- End of line seen             */
  917.         default:                        /* Junk or end of file seen     */
  918.             cerror("Unterminated multi-character constant", NULLST);
  919.             break;
  920.         }
  921.         instring = FALSE;
  922.         return (value);
  923. }
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936.  
  937.  
  938.  
  939.  
  940. FILE_LOCAL int
  941. evalone()
  942. /*
  943.  * Called from evalchar() above to get a single character with \ escapes.
  944.  * Returns the character or EOF_CHAR (on errors).
  945.  */
  946. {
  947.         register char   *cp;
  948.         register char   *digits;
  949.         register int    c;
  950.         register int    value;
  951.         register int    count;
  952.         extern char     *strchr();
  953.  
  954.         switch (c = cget()) {
  955.         default:
  956.             return (c);
  957.  
  958.         case '\n':
  959.         case '\'':
  960.             unget();
  961.             return (EOF_CHAR);                  /* Exits mult-char loop */
  962.  
  963.         case '\\':                              /* \ escape seen        */
  964.             break;
  965.         }
  966.         switch (c = cget()) {
  967.         case 'a':                               /* New in Standard      */
  968. #if ('a' == '\a' || '\a' == ALERT)
  969.             return (ALERT);                     /* Use predefined value */
  970. #else
  971.             return ('\a');                      /* Use compiler's value */
  972. #endif
  973.  
  974.         case 'b':
  975.             return ('\b');
  976.  
  977.         case 'f':
  978.             return ('\f');
  979.  
  980.         case 'n':
  981.             return ('\n');
  982.  
  983.         case 'r':
  984.             return ('\r');
  985.  
  986.         case 't':
  987.             return ('\t');
  988.  
  989.         case 'v':                               /* New in Standard      */
  990. #if ('v' == '\v' || '\v' == VT)
  991.             return (VT);                        /* Use predefined value */
  992. #else
  993.             return ('\v');                      /* Use compiler's value */
  994. #endif
  995.  
  996.         case 'x':                               /* '\xFF'               */
  997.             digits = "0123456789abcdef";
  998.             c = cget();
  999.             break;
  1000.  
  1001.         case '0': case '1': case '2': case '3':
  1002.         case '4': case '5': case '6': case '7':
  1003.             digits = "01234567";
  1004.             break;
  1005.  
  1006.         default:
  1007.             return (c);
  1008.         }
  1009.         value = 0;
  1010.         for (count = 0; count < 3; ++count) {
  1011.             if (c == EOF_CHAR)
  1012.                 return (c);
  1013.             if (isascii(c) && isupper(c))
  1014.                 c = tolower(c);
  1015.             if ((cp = strchr(digits, c)) == 0)
  1016.                 break;
  1017.             value = value * strlen(digits) + cp - digits;
  1018.             c = cget();
  1019.         }
  1020.         unget();
  1021.         if (count == 0)                         /* '\xnonsense'         */
  1022.             return (EOF_CHAR);
  1023.         return (value);
  1024. }
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036. FILE_LOCAL double *
  1037. evaleval(valp, op, skip)
  1038. register double *valp;
  1039. int             op;
  1040. int             skip;           /* TRUE if short-circuit evaluation     */
  1041. /*
  1042.  * Apply the argument operator to the data on the value stack.
  1043.  * One or two values are popped from the value stack and the result
  1044.  * is pushed onto the value stack.
  1045.  *
  1046.  * OP_COL is a special case.
  1047.  *
  1048.  * evaleval() returns the new pointer to the top of the value stack.
  1049.  */
  1050. {
  1051.         register double v1, v2;
  1052.  
  1053.         if (isbinary(op))
  1054.             v2 = *--valp;
  1055.         v1 = *--valp;
  1056. #ifdef  DEBUG_EVAL
  1057.         printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
  1058.             opname[op]);
  1059.         if (isbinary(op))
  1060.             printf(", v2 = %f.", v2);
  1061.         printf(", v1 = %f.\n", v1);
  1062. #endif
  1063.         switch (op) {
  1064.         case OP_EOE:
  1065.              break;
  1066.  
  1067.         case OP_ADD:
  1068.             v1 += v2;
  1069.             break;
  1070.  
  1071.         case OP_SUB:
  1072.             v1 -= v2;
  1073.             break;
  1074.  
  1075.         case OP_MUL:
  1076.             v1 *= v2;
  1077.             break;
  1078.  
  1079.         case OP_DIV:
  1080.         case OP_MOD:
  1081.             if (v2 == 0) {
  1082.                 if (!skip) {
  1083.                     cwarn("%s by zero in #if, zero result assumed",
  1084.                         (op == OP_DIV) ? "divide" : "mod");
  1085.                 }
  1086.                 v1 = 0;
  1087.             }
  1088.             else if (op == OP_DIV)
  1089.                 v1 /= v2;
  1090.             else
  1091.                 v1 = (long) v1 % (long) v2;
  1092.             break;
  1093.  
  1094.         case OP_ASL:
  1095.             v1 = (long) v1 << (long) v2;
  1096.             break;
  1097.  
  1098.         case OP_ASR:
  1099.             v1 = (long) v1 >> (long) v2;
  1100.             break;
  1101.  
  1102.         case OP_AND:
  1103.             v1 = (long) v1 & (long) v2;
  1104.             break;
  1105.  
  1106.         case OP_OR:
  1107.             v1 = (long) v1 | (long) v2;
  1108.             break;
  1109.  
  1110.         case OP_XOR:
  1111.             v1 = (long) v1 ^ (long) v2;
  1112.             break;
  1113.  
  1114.         case OP_EQ:
  1115.             v1 = (v1 == v2);
  1116.             break;
  1117.  
  1118.         case OP_NE:
  1119.             v1 = (v1 != v2);
  1120.             break;
  1121.  
  1122.         case OP_LT:
  1123.             v1 = (v1 < v2);
  1124.             break;
  1125.  
  1126.         case OP_LE:
  1127.             v1 = (v1 <= v2);
  1128.             break;
  1129.  
  1130.         case OP_GE:
  1131.             v1 = (v1 >= v2);
  1132.             break;
  1133.  
  1134.         case OP_GT:
  1135.             v1 = (v1 > v2);
  1136.             break;
  1137.  
  1138.         case OP_ANA:
  1139.             v1 = (v1 && v2);
  1140.             break;
  1141.  
  1142.         case OP_ORO:
  1143.             v1 = (v1 || v2);
  1144.             break;
  1145.  
  1146.         case OP_COL:
  1147.             /*
  1148.              * v1 has the "true" value, v2 the "false" value.
  1149.              * The top of the value stack has the test.
  1150.              */
  1151.             v1 = (*--valp) ? v1 : v2;
  1152.             break;
  1153.  
  1154.         case OP_NEG:
  1155.             v1 = (-v1);
  1156.             break;
  1157.  
  1158.         case OP_PLU:
  1159.             break;
  1160.  
  1161.         case OP_COM:
  1162.             v1 = ~((long) v1);
  1163.             break;
  1164.  
  1165.         case OP_NOT:
  1166.             v1 = !v1;
  1167.             break;
  1168.  
  1169.         default:
  1170.             cierror("#if bug, operand = %d.", op);
  1171.             v1 = 0;
  1172.         }
  1173.         *valp++ = v1;
  1174.         return (valp);
  1175. }
  1176.  
  1177.  
  1178.  
  1179.  
  1180. #ifdef  DEBUG_EVAL
  1181. dumpstack(opstack, opp, value, valp)
  1182. OPTAB           opstack[NEXP];  /* Operand stack                */
  1183. register OPTAB  *opp;           /* Operator stack               */
  1184. double          value[NEXP];    /* Value stack                  */
  1185. register double *valp;          /* -> value vector              */
  1186. {
  1187.         printf("index op prec skip name -- op stack at %s", infile->bptr);
  1188.         while (opp > opstack) {
  1189.             printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
  1190.                 opp->op, opp->prec, opp->skip, opname[opp->op]);
  1191.             opp--;
  1192.         }
  1193.         while (--valp >= value) {
  1194.             printf("value[%d] = %f\n", (valp - value), *valp);
  1195.         }
  1196. }
  1197. #endif
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204. From:   RHEA::DECWRL::"elsie!ado@seismo.ARPA" 11-JUN-1985 15:58
  1205. To:     seismo!minow%rex.DEC@decwrl
  1206. Subj:   cpp5.c delinting
  1207.  
  1208. Received: from DECWRL by DEC-RHEA with SMTP; Tue, 11 Jun 85 12:58-PDT
  1209. Received: from seismo.ARPA (seismo.arpa.ARPA) by decwrl.ARPA (4.22.01/4.7.34)
  1210.         id AA21249; Tue, 11 Jun 85 12:57:52 pdt
  1211. Received: from elsie.UUCP by seismo.ARPA with UUCP; Tue, 11 Jun 85 15:57:31 EDT
  1212. Date: Tue, 11 Jun 85 15:57:31 EDT
  1213. Return-Path: <elsie!ado@seismo.ARPA>
  1214. Message-Id: <8506111957.AA14370@seismo.ARPA>
  1215.  
  1216. A couple of delinting changes to the new "cpp5.c". . .changes to the function
  1217. "purenumb" and to the declarations in "evalnum":
  1218.  
  1219.         FILE_LOCAL double
  1220.         purenumb(base, resultp)
  1221.         double *        resultp;
  1222.         {
  1223.                 register int    digits;
  1224.                 register int    new;
  1225.                 register int    c;
  1226.  
  1227.                 *resultp = 0;
  1228.                 digits = 0;
  1229.                 for ( ; ; ) {
  1230.                         c = cget();
  1231.                         new = ctoi(c);
  1232.                         if (new < 0 || new >= base) {
  1233.                                 unget();
  1234.                                 return digits;
  1235.                         }
  1236.                         *resultp = *resultp * base + new;
  1237.                         ++digits;
  1238.                 }
  1239.         }
  1240.  
  1241.         FILE_LOCAL double
  1242.         evalnum(c)
  1243.         register int    c;
  1244.         /*
  1245.          * Expand number for #if lexical analysis.  Note: evalnum recognizes
  1246.          * the unsigned suffix, but only returns a signed int value.
  1247.          * c may be '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', or '.'.
  1248.          */
  1249.         {
  1250.                 register int    base;
  1251.                 register int    ucount, lcount;
  1252.                 register int    expsignchar;
  1253.                 double          result, fracpart, exppart;
  1254.                 register int    intdigs, fracdigs;
  1255.  
  1256.                                 --ado
  1257.  
  1258.